﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace mimosa.SIP
{
    public class SIPConstants
    {
        public const string CRLF = "\r\n";

        public const string SIP_VERSION_STRING = "SIP";
        public const int SIP_MAJOR_VERSION = 2;
        public const int SIP_MINOR_VERSION = 0;
        public const string SIP_FULLVERSION_STRING = "SIP/2.0";

        public const int NONCE_TIMEOUT_MINUTES = 5;							// Length of time an issued nonce is valid for.
        public const int SIP_MAXIMUM_LENGTH = 2048;							// Any SIP messages over this size will generate an error.
        public const string SIP_PROTOCOL_STRING = "UDP";
        public const string SIP_USERAGENT_STRING = "mimosa-ua-v0.0.1";
        public const string SIP_PROXYUSERAGENT_STRING = "mimosa-sipproxy";
        public const string SIP_REQUEST_REGEX = @"^\w+ .* SIP/.*";			// bnf:	Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
        public const string SIP_RESPONSE_REGEX = @"^SIP/.* \d{3}";			// bnf: Status-Line  =  SIP-Version SP Status-Code SP Reason-Phrase CRLF
        public const string SIP_BRANCH_MAGICCOOKIE = "z9hG4bK";
        public const string SIP_ROUTE_TRANSPORT = "sip";
        public const string SIP_DEFAULT_USERNAME = "Anonymous";
        public const string SIP_DEFAULT_FROMURI = "sip:thisis@anonymous.invalid";
        public const string SIP_REGISTER_REMOVEALL = "*";					// The value in a REGISTER request id a UA wishes to remove all REGISTER bindings.
        public const string SIP_LOOSEROUTER_PARAMETER = "lr";

        public const int DEFAULT_MAX_FORWARDS = 70;
        public const int DEFAULT_REGISTEREXPIRY_SECONDS = 600;
        public const int DEFAULT_SIP_PORT = 5060;
        public const int TRANSACTION_LIFETIME_SECONDS = 30;

        public const int DEFAULT_STARTRTP_PORT = 10000;
        public const int DEFAULT_ENDRTP_PORT = 20000;

        public const int MAX_PORT = 65535;

        public const string MWI_CONTENT_TYPE = "application/simple-message-summary";
        public const string NAT_SENDKEEPALIVES_VALUE = "y";
    }

    public class SIPTimings
    {
        public const int T1 = 500;      // Value of SIP defined timer T1 in milliseconds.
        public const int T6 = 64 * T1;
    }

    public class SIPHeaders
    {
        // SIP Header Keys.
        public const string SIP_HEADER_ACCEPT = "Accept";
        public const string SIP_HEADER_AUTHORIZATION = "Authorization";
        public const string SIP_HEADER_CALLID = "Call-ID";
        public const string SIP_HEADER_CONTACT = "Contact";
        public const string SIP_HEADER_CONTENTLENGTH = "Content-Length";
        public const string SIP_HEADER_CONTENTTYPE = "Content-Type";
        public const string SIP_HEADER_CSEQ = "CSeq";
        public const string SIP_HEADER_DATE = "Date";
        public const string SIP_HEADER_EXPIRES = "Expires";
        public const string SIP_HEADER_FROM = "From";
        public const string SIP_HEADER_MAXFORWARDS = "Max-Forwards";
        public const string SIP_HEADER_PROXYAUTHENTICATION = "Proxy-Authenticate";
        public const string SIP_HEADER_PROXYAUTHORIZATION = "Proxy-Authorization";
        public const string SIP_HEADER_RECORDROUTE = "Record-Route";
        public const string SIP_HEADER_REFERREDBY = "Referred-By";
        public const string SIP_HEADER_REFERTO = "Refer-To";
        public const string SIP_HEADER_REQUIRE = "Require";
        public const string SIP_HEADER_ROUTE = "Route";
        public const string SIP_HEADER_SERVER = "Server";
        public const string SIP_HEADER_TIMESTAMP = "Timestamp";
        public const string SIP_HEADER_TO = "To";
        public const string SIP_HEADER_USERAGENT = "User-Agent";
        public const string SIP_HEADER_VIA = "Via";
        public const string SIP_HEADER_WWWAUTHENTICATE = "WWW-Authenticate";

        // SIP Compact Header Keys.
        public const string SIP_COMPACTHEADER_CALLID = "i";
        public const string SIP_COMPACTHEADER_CONTACT = "m";
        public const string SIP_COMPACTHEADER_FROM = "f";
        public const string SIP_COMPACTHEADER_TO = "t";
        public const string SIP_COMPACTHEADER_CONTENTLENGTH = "l";
        public const string SIP_COMPACTHEADER_CONTENTTYPE = "c";
        public const string SIP_COMPACTHEADER_VIA = "v";

        // SIP Header Extensions for SIP Event Package RFC 3265.
        public const string SIP_HEADER_EVENT = "Event";
        public const string SIP_HEADER_SUBSCRIPTIONSTATE = "Subscription-State";
    }

    public class SIPHeaderAncillary
    {
        public const string SIP_HEADERANC_TAG = "tag";
        public const string SIP_HEADERANC_RPORT = "rport";
        public const string SIP_HEADERANC_BRANCH = "branch";
        public const string SIP_HEADERANC_RECEIVED = "received";
    }

    /// <summary>
    /// Authorization Headers
    /// </summary>
    public class AuthHeaders
    {
        public const string AUTH_DIGEST_KEY = "Digest";
        public const string AUTH_REALM_KEY = "realm";
        public const string AUTH_NONCE_KEY = "nonce";
        public const string AUTH_USERNAME_KEY = "username";
        public const string AUTH_RESPONSE_KEY = "response";
        public const string AUTH_URI_KEY = "uri";
        public const string AUTH_ALGORITHM_KEY = "algorithm";
    }

    public enum SIPMessageTypesEnum
    {
        Unknown = 0,
        Request = 1,
        Response = 2,
    }

    public enum SIPResponseStatusCodesEnum
    {
        // Informational
        Trying = 100,
        Ringing = 180,
        CallIsBeingForwarded = 181,
        Queued = 182,
        SessionProgress = 183,

        // Success
        Ok = 200,

        // Redirection
        MultipleChoices = 300,
        MovedPermanently = 301,
        MovedTemporarily = 302,
        UseProxy = 303,
        AlternativeService = 304,

        // Client-Error
        BadRequest = 400,
        Unauthorised = 401,
        PaymentRequired = 402,
        Forbidden = 403,
        NotFound = 404,
        MethodNotAllowed = 405,
        NotAcceptable = 406,
        ProxyAuthenticationRequired = 407,
        RequestTimeout = 408,
        Gone = 409,
        RequestEntityTooLarge = 413,
        RequestURITooLarge = 414,
        UnsupportedMediaType = 415,
        UnsupportedURIScheme = 416,
        BadExtension = 420,
        ExtensionRequired = 421,
        IntervalTooBrief = 423,
        TemporarilyNotAvailable = 480,
        CallLegTransactionDoesNotExist = 481,
        LoopDetected = 482,
        TooManyHops = 483,
        AddressIncomplete = 484,
        Ambiguous = 485,
        BusyHere = 486,
        RequestTerminated = 487,
        NotAcceptableHere = 488,
        RequestPending = 491,
        Undecipherable = 493,

        // Server-Error
        InternalServerError = 500,
        NotImplemented = 501,
        BadGateway = 502,
        ServerTimeout = 504,
        SIPVersionNotSupported = 505,
        MessageTooLarge = 513,

        // Global-Failure
        BusyEverywhere = 600,
        Decline = 603,
        DoesNotExistAnywhere = 604,
        NotAcceptableAnywhere = 606,
    }

    public enum SIPMethodsEnum
    {
        NONE = 0,
        UNKNOWN = 1,

        // Core.
        REGISTER = 2,
        INVITE = 3,
        BYE = 4,
        ACK = 5,
        CANCEL = 6,
        OPTIONS = 7,

        INFO = 8,
        NOTIFY = 9,
        SUBSCRIBE = 10,
        PUBLISH = 11,
        PING = 13,
        REFER = 14,
    }

    public class SIPMethods
    {
        public static SIPMethodsEnum GetMethod(string method)
        {
            SIPMethodsEnum sipMethod = SIPMethodsEnum.UNKNOWN;

            try
            {
                sipMethod = (SIPMethodsEnum)Enum.Parse(typeof(SIPMethodsEnum), method, true);
            }
            catch { }

            return sipMethod;
        }
    }
    public class SIPResponseStatusCodes
    {
        public static SIPResponseStatusCodesEnum GetStatusTypeForCode(int statusCode)
        {
            return (SIPResponseStatusCodesEnum)Enum.Parse(typeof(SIPResponseStatusCodesEnum), statusCode.ToString(), true);
        }
    }

    public enum SIPUserAgentRoles
    {
        Unknown = 0,
        Client = 1,
        Server = 2,
    }
}
